package com.charging.business.gantry;

import com.charging.business.constants.LibraryThread;
import com.charging.business.dao.FeeDll;
import com.charging.business.dao.GantryFee;
import com.charging.business.domain.FeeEntryInfoModel;
import com.charging.business.enums.FreeModelEnumRes;
import com.charging.business.enums.GantryFeeErrorEnum;
import com.charging.business.enums.SpecialSituation;
import com.charging.business.exception.CustomizeException;
import com.charging.business.utils.BasicUtil;
import com.charging.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 动态库计费service
 *
 * @author JerryLu
 * @date 2024/8/25 17:14
 * @return
 */
@Service
public class GantryCalcUtils {
    private final Logger logger = LoggerFactory.getLogger(GantryCalcUtils.class);

    @Autowired
    private LibraryThread feeThread;

    /**
     * 动态库计费
     *
     * @param entryInfoModelDto
     * @return
     * @throws CustomizeException
     */
    public EntryFeeCalcResponse libraryFee(FeeEntryInfoModel entryInfoModelDto) throws CustomizeException {
        int code = 0;
            GantryFee gantryFee = this.getGantryFee(entryInfoModelDto);
            code = gantryFee.getFeeCalcResult();
            EntryFeeCalcResponse responseDto = toCalcFeeModelDetail(gantryFee);
            if (null != gantryFee && gantryFee.isSuccess()) {
                responseDto.setCode(0);
                responseDto.setMsg("计费成功");
            } else {
                responseDto.setCode(-1);
                responseDto.setMsg(FreeModelEnumRes.fromValue(code).getDescription());
            }
            return responseDto;
    }

    /**
     * 门架计费
     *
     * @param calcFeeInfoModel
     * @return com.ruoyi.business.domain.GantryFee
     * @author JerryLu
     * @date 2024/8/11 15:59
     */
    private GantryFee getGantryFee(FeeEntryInfoModel calcFeeInfoModel) {
        try {
            String gantryId = calcFeeInfoModel.getCurTollGantry();
            FeeDll feeDll = feeThread.getFeeDll(gantryId);
            if (null == feeDll) {
                logger.error("未加载门架计费动态库");
                return null;
            }
            Feecalc feecalc = feeDll.getFeecalc();
            Feecalc.TradingInfo.ByReference tradingInfo = new Feecalc.TradingInfo.ByReference();
            tradingInfo.curTollGantry = StringUtils.getBytes0(calcFeeInfoModel.getCurTollGantry(), tradingInfo.curTollGantry);
            tradingInfo.curPassTime = StringUtils.getBytes0(calcFeeInfoModel.getCurPassTime(), tradingInfo.curPassTime);
            tradingInfo.laneStatus = calcFeeInfoModel.getLaneStatus();
            tradingInfo.enTollStationHex = StringUtils.getBytes0(calcFeeInfoModel.getEnTollStationHex(), tradingInfo.enTollStationHex);
            tradingInfo.enPassTime = StringUtils.getBytes0(calcFeeInfoModel.getEnPassTime(), tradingInfo.enPassTime);
            tradingInfo.lastGantryHex = StringUtils.getBytes0(StringUtils.isBlank(calcFeeInfoModel.getLastGantryHex()) ? "" : calcFeeInfoModel.getLastGantryHex(), tradingInfo.lastGantryHex);
            LocalDateTime lastPassTime = calcFeeInfoModel.getLastPassTime();
            String lastPassTimeStr = null == lastPassTime ? "" : lastPassTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"));
            tradingInfo.lastPasstime = StringUtils.getBytes0(lastPassTimeStr, tradingInfo.lastPasstime);
            tradingInfo.lastGantryFee = null == calcFeeInfoModel.getLastGantryFee() ? 0 : calcFeeInfoModel.getLastGantryFee();
            tradingInfo.lastFeeMileage = null == calcFeeInfoModel.getLastFeeMileage() ? 0 : calcFeeInfoModel.getLastFeeMileage();
            tradingInfo.issuerId = StringUtils.getBytes0(calcFeeInfoModel.getIssuerId(), tradingInfo.issuerId);
            tradingInfo.cardNetwork = StringUtils.getBytes0(calcFeeInfoModel.getCardNetwork(), tradingInfo.cardNetwork);
            tradingInfo.vehicleUserType = calcFeeInfoModel.getVehicleUserType();
            tradingInfo.axleCount = calcFeeInfoModel.getAxleCount();
            tradingInfo.enAxleCount = calcFeeInfoModel.getEnAxleCount();
            tradingInfo.tagType = calcFeeInfoModel.getTagType();
            tradingInfo.cardType = calcFeeInfoModel.getCardType();
            tradingInfo.cardVer = calcFeeInfoModel.getCardVer();
            tradingInfo.obuSn = StringUtils.getBytes0(calcFeeInfoModel.getObuSn(), tradingInfo.obuSn);
            tradingInfo.cpuCardId = StringUtils.getBytes0(calcFeeInfoModel.getCpuCardId(), tradingInfo.cpuCardId);
            tradingInfo.plateHex = StringUtils.getBytes0(calcFeeInfoModel.getPlateHex(), tradingInfo.plateHex);
            tradingInfo.plateColor = calcFeeInfoModel.getPlateColor().shortValue();
            tradingInfo.vehicleType = calcFeeInfoModel.getVehicleType();
            tradingInfo.enVehicleType = calcFeeInfoModel.getEnVehicleType();
            tradingInfo.vehicleClass = calcFeeInfoModel.getVehicleClass();
            tradingInfo.feeSumLocal = calcFeeInfoModel.getFeeSumLocal();
            tradingInfo.vehicleWeightLimits = calcFeeInfoModel.getVehicleWeightLimits();
            tradingInfo.totalWeight = calcFeeInfoModel.getTotalWeight();
            tradingInfo.vehicleStatusFlag = calcFeeInfoModel.getVehicleStatusFlag();
            tradingInfo.feeProvBeginHex = StringUtils.getBytes0(calcFeeInfoModel.getFeeProvBeginHex(), tradingInfo.feeProvBeginHex);
            tradingInfo.feeProvMileage = calcFeeInfoModel.getFeeProvMileage();
            tradingInfo.feeProvGantryNum = calcFeeInfoModel.getFeeProvGantryNum();
            tradingInfo.payFeeSumLocal = calcFeeInfoModel.getPayFeeSumLocal();
            tradingInfo.realFeeSumLocal = calcFeeInfoModel.getRealFeeSumLocal();
            tradingInfo.gantryPassNum = calcFeeInfoModel.getGantryPassNum();
            tradingInfo.gantryPassHex = StringUtils.getBytes0(calcFeeInfoModel.getGantryPassHex(), tradingInfo.gantryPassHex);
            tradingInfo.Spare1 = null == calcFeeInfoModel.getSpare1() ? 0 : calcFeeInfoModel.getSpare1();
            tradingInfo.Spare2 = null == calcFeeInfoModel.getSpare2() ? 0 : calcFeeInfoModel.getSpare2();
            tradingInfo.Spare3 = null == calcFeeInfoModel.getSpare3() ? 0 : calcFeeInfoModel.getSpare3();
            tradingInfo.Spare4 = StringUtils.getBytes0(calcFeeInfoModel.getSpare4(), tradingInfo.Spare4);
            tradingInfo.Spare5 = StringUtils.getBytes0(calcFeeInfoModel.getSpare5(), tradingInfo.Spare5);
            return this.getGantryFee(feeDll, feecalc, tradingInfo);
        } catch (Throwable t) {
            logger.error(String.valueOf(t), t);
            return null;
        }
    }

    /**
     * 获取门架费用
     *
     * @param feeDll
     * @param feecalc
     * @param tradingInfo
     * @return com.ruoyi.business.domain.GantryFee
     * @author JerryLu
     * @date 2024/8/11 16:00
     */
    private GantryFee getGantryFee(FeeDll feeDll, Feecalc feecalc, Feecalc.TradingInfo.ByReference tradingInfo) {
        Feecalc.FeeInfo.ByReference feeInfo = new Feecalc.FeeInfo.ByReference();
        Feecalc.FeeInfoByHex.ByReference feeInfoByHex = new Feecalc.FeeInfoByHex.ByReference();
        long start = System.currentTimeMillis();
        int i;
        i = feecalc.getFee(tradingInfo, feeInfo);
        long now = System.currentTimeMillis();
        GantryFee gantryFee = new GantryFee();
        gantryFee.setFeeCalcResult(i);
        gantryFee.setConsumeTime(now - start);
        gantryFee.setTradingInfo(tradingInfo);
        gantryFee.setFeeInfo(feeInfo);
        GantryFeeErrorEnum errorEnum = GantryFeeErrorEnum.getInstanceByValue(i);
//        logger.info("获取门架费用结果: {}=={}, 用时{}毫秒", errorEnum, i, now - start);
        if (null == errorEnum) {
            logger.error("获取门架费用失败:" + new String(feeInfo.feeLogMsg).trim());
            BasicUtil.setSpecialInfo(SpecialSituation.TYPE63.getValue());
            gantryFee.setSuccess(false);
        } else if (GantryFeeErrorEnum.NO_ERROR == errorEnum) {
            gantryFee.setFeeInfo(feeInfo);
            gantryFee.setFeeInfoByHex(feeInfoByHex);
            gantryFee.setTradingInfo(tradingInfo);
            gantryFee.setDllVersion(feeDll.getDllVersion());
            gantryFee.setSuccess(true);
        } else {
            logger.error("获取门架费用失败:" + new String(feeInfo.feeLogMsg).trim());
            BasicUtil.setSpecialInfo(SpecialSituation.TYPE63.getValue());
        }
        return gantryFee;
    }


    /**
     * 门架计费明细转换
     *
     * @param gantryFee
     * @return
     */
    private EntryFeeCalcResponse toCalcFeeModelDetail(GantryFee gantryFee) {
        return this.toCalcFeeModelDetail(gantryFee.getFeeInfo(), gantryFee.getDllVersion(), gantryFee);
    }

    /**
     * 计算计费结果明细，转换返回对应实体信息
     *
     * @param feeInfo
     * @param dllVersion
     * @return com.ruoyi.business.config.GsCalcFeeModelDetail
     * @author JerryLu
     * @date 2024/8/11 15:57
     */
    private EntryFeeCalcResponse toCalcFeeModelDetail(Feecalc.FeeInfo feeInfo, String dllVersion, GantryFee gantryFee) {
        EntryFeeCalcResponse responseDto = new EntryFeeCalcResponse();
        responseDto.setPayFee(feeInfo.payFee);
        responseDto.setDiscountFee(feeInfo.discountFee);
        responseDto.setRealFee(feeInfo.realFee);
        responseDto.setCardFee(feeInfo.cardFee);
        responseDto.setFeeProvSumLocal(feeInfo.feeProvSumLocal);
        byte[] buffer = feeInfo.paramVersion;
        String paramVersion = new String(buffer).trim();
        String gantryVersion = getGantryVersion(dllVersion, paramVersion);
        responseDto.setParamVersion(gantryVersion);
        responseDto.setFeeSpecial(new String(feeInfo.feeSpecial).trim());
        responseDto.setFitResult(feeInfo.fitResult);
        responseDto.setTollInterValIds(new String(feeInfo.tollIntervalIDs).trim());
        responseDto.setPayFeeGroup(new String(feeInfo.payFeeGroup).trim());
        responseDto.setDiscountFeeGroup(new String(feeInfo.discountFeeGroup).trim());
        responseDto.setFeeGroup(new String(feeInfo.feeGroup).trim());
        responseDto.setFeeInfo1(new String(feeInfo.feeInfo1).trim());
        responseDto.setFeeInfo2(new String(feeInfo.feeInfo2).trim());
        responseDto.setFeeInfo3(new String(feeInfo.feeInfo3).trim());
        responseDto.setFeeLogMsg(new String(feeInfo.feeLogMsg).trim());
        responseDto.setFeeVehicleType(feeInfo.feeVehicleType);
        responseDto.setFeeMileage(feeInfo.feeMileage);
        responseDto.setProvMinFee(new String(feeInfo.provMinFee).trim());
        responseDto.setFeeProvBeginHexFit(new String(feeInfo.feeProvBeginHexFit).trim());
        responseDto.setFeeProvBeginTimeFit(new String(feeInfo.feeProvBeginTimeFit).trim());
        responseDto.setFitProvFlag(feeInfo.fitProvFlag);
        responseDto.setGantryPassNumFit(feeInfo.gantryPassNumFit);
        responseDto.setGantryPassHexFit(new String(feeInfo.gantryPassHexFit).trim());
        responseDto.setFeeSpare1(feeInfo.feeSpare1);
        responseDto.setFeeSpare2(feeInfo.feeSpare2);
        responseDto.setFeeSpare3(new String(feeInfo.feeSpare3).trim());
        responseDto.setCalCostTime(gantryFee.getConsumeTime());
        responseDto.setSuccess(gantryFee.isSuccess());
        responseDto.setMsg(FreeModelEnumRes.fromValue(gantryFee.getFeeCalcResult()).getDescription());
        return responseDto;
    }

    /**
     * 门架计费明细转换
     *
     * @param feeInfoByHex
     * @param dllVersion
     * @return com.ruoyi.business.config.GsCalcFeeModelDetail
     * @author JerryLu
     * @date 2024/8/11 15:58
     */
    private EntryFeeCalcResponse toCalcFeeModelDetail(Feecalc.FeeInfoByHex feeInfoByHex, String dllVersion) {
        EntryFeeCalcResponse responseDto = new EntryFeeCalcResponse();
        responseDto.setPayFee(feeInfoByHex.payFee);
        responseDto.setDiscountFee(feeInfoByHex.discountFee);
        responseDto.setRealFee(feeInfoByHex.realFee);
        responseDto.setCardFee(feeInfoByHex.cardFee);
        responseDto.setFeeProvSumLocal(feeInfoByHex.feeProvSumLocal);
        byte[] buffer = feeInfoByHex.paramVersion;
        String paramVersion = new String(buffer).trim();
        String gantryVersion = getGantryVersion(dllVersion, paramVersion);
        responseDto.setParamVersion(gantryVersion);
        responseDto.setFeeSpecial(new String(feeInfoByHex.feeSpecial).trim());
        responseDto.setFitResult(feeInfoByHex.fitResult);
        responseDto.setTollInterValIds(new String(feeInfoByHex.tollIntervalIDs).trim());
        responseDto.setPayFeeGroup(new String(feeInfoByHex.payFeeGroup).trim());
        responseDto.setDiscountFeeGroup(new String(feeInfoByHex.discountFeeGroup).trim());
        responseDto.setFeeGroup(new String(feeInfoByHex.feeGroup).trim());
        responseDto.setFeeVehicleType(feeInfoByHex.feeVehicleType);
        responseDto.setFeeMileage(feeInfoByHex.feeVehicleType);
        responseDto.setProvMinFee(new String(feeInfoByHex.provMinFee).trim());
        responseDto.setFeeProvBeginHexFit(new String(feeInfoByHex.feeProvBeginHexFit).trim());
        responseDto.setFeeProvBeginTimeFit(new String(feeInfoByHex.feeProvBeginTimeFit).trim());
        responseDto.setFitProvFlag(feeInfoByHex.fitProvFlag);
        responseDto.setGantryPassNumFit(feeInfoByHex.gantryPassNumFit);
        responseDto.setGantryPassHexFit(new String(feeInfoByHex.gantryPassHexFit).trim());
        responseDto.setFeeSpare1(feeInfoByHex.feeSpare1);
        responseDto.setFeeSpare2(feeInfoByHex.feeSpare2);
        responseDto.setFeeSpare3(new String(feeInfoByHex.feeSpare3).trim());
        return responseDto;
    }

    /**
     * 计费模块版本号与计费参数版本号使用“|”分隔。
     * 无则填“0”
     *
     * @param dllVersion
     * @param paramVersion
     * @return java.lang.String
     * @author JerryLu
     * @date 2024/8/11 15:57
     */
    private String getGantryVersion(String dllVersion, String paramVersion) {
        if (null == dllVersion || paramVersion.isEmpty()) {
            return "0";
        } else {
            return dllVersion + "|" + paramVersion;
        }
    }
}

